Access violation v konstruktoru

Otázka od: Jaromir Cermak

22. 11. 2004 10:43

Ahoj vsichni

Mam nasledujici problem a zoufale prosim o pomoc. Vytvoril jsem si vlastni
formular s vlastnim konstruktorem. Jako prvni prikaz se vola inherited
create(AOwner) a ten zpusobi pad s AV.

Pri podrobnejsim krokovani pres unity delphi jsem si vsiml nasledujicich veci:

v unite system se jeste pred inherited vola funkce ClassCreate. V ni se
preskoci instrukce

CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance

v DL je hodnota 255

pri krokovani TCustomForm.Create mi to spadne na volani CreateNew(AOwner);

V konstruktoru jsem pouzival virtualni metodu, ale ani jeji odstraneni mi
nepomohlo. Nevite kde delam chybu? Prosim poradte.



                                            Jaromir Cermak


Odpovedá: Petr Brant

22. 11. 2004 12:11

Formulare s vlastnim konstruktorem tvorim casto a bez problemu. Ale namisto
AOwner pisu nil:

constructor TActivityWnd.Create(VehTable: TTable; FBWrap: TFBWrap;
MapBinWork: TMapBinWork2);
begin
 inherited Create(nil);
 VehIDList:= TIntegerList.Create;
 self.VehTable:= VehTable;
 self.FBWrap:= FBWrap;
 self.MapBinWork:= MapBinWork;
....

a vyvolani formulare delam takto:

ActivityWnd:= TActivityWnd.Create(VehTable, FBWrap, MapBinWork);
ActivityWnd.ShowModal;
ActivityWnd.Free;

Zkus to take tak, nikdy jsem s tim problemy nemel.

RNDr. Petr Brant [brant@dcomm.cz]
http://brant.wz.cz



Mam nasledujici problem a zoufale prosim o pomoc. Vytvoril jsem si vlastni
formular s vlastnim konstruktorem. Jako prvni prikaz se vola inherited
create(AOwner) a ten zpusobi pad s AV.

Pri podrobnejsim krokovani pres unity delphi jsem si vsiml nasledujicich
veci:

v unite system se jeste pred inherited vola funkce ClassCreate. V ni se
preskoci instrukce

CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance

v DL je hodnota 255

pri krokovani TCustomForm.Create mi to spadne na volani CreateNew(AOwner);

V konstruktoru jsem pouzival virtualni metodu, ale ani jeji odstraneni mi
nepomohlo. Nevite kde delam chybu?

Odpovedá: Jaromir Cermak

22. 11. 2004 12:12

Taky to neni poprve co delam vlastni konstruktor, spis premyslim proc se
preskoci instrukce



CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance.

Zaujalo me ze v registru DL je 255. Probehne li vse normalne, je tam 1.

Ale mozna ze premyslim scestne a jeno neco nevidim. Nevite na co si dat pozor?


                                            Jaromir Cermak


Odpovedá: Petr Fejfar

22. 11. 2004 12:30

Jaromir Cermak wrote:

> Taky to neni poprve co delam vlastni konstruktor, spis premyslim proc
> se preskoci instrukce

Mohl bys pls specifikovat, co mas na mysli tim "preskoci se"?

To jako ze ti debugger ukaze, ze instrukci vykonavana, ale zadna subrutina
se
nezavola?

V tom pripade bych rek, ze debugger ukazuje buhvi co resp.
ze mapa cisel radku z prekladu neodpovida trasovanemu zdrojovemu kodu.

pf



Odpovedá: delphin@post.cz

22. 11. 2004 13:00

> Taky to neni poprve co delam vlastni konstruktor, spis premyslim proc se
preskoci instrukce
> CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance.
> Zaujalo me ze v registru DL je 255. Probehne li vse normalne, je tam 1.

Konstruktor je fyzicky: inicialize tridy + metoda + volani
AfterConstruction. Pri volani prvniho konstruktoru se konstruktor vola
normalne, tedy vcetne inicializace a AfterConstruction. Pokud se z
konstruktoru vola konstruktor predka, nevola se uz jako konstruktor, ale
jako standardni procedura. V DL se predava specialni parametr, ktery
rozhoduje o tom, zda se vola jako konstruktor nebo jako metoda.


Odpovedá: Jaromir Cermak

22. 11. 2004 13:49

Ne.

ve funkci:

function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
asm
        { -> EAX = pointer to VMT }
        { <- EAX = pointer to instance }
        PUSH EDX
        PUSH ECX
        PUSH EBX
        TEST DL,DL
        JL @@noAlloc
        CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance
@@noAlloc:

z unity systeM se po instrukci TEST provede JL ktery dany CALL preskoci.
Debugger ukazuje ze DL=255, u formulare kde je vsechno v poradku DL=1. Nevim
proc k tomu dojde.

Konstruktor vypada takto:

constructor TFORP_EditProtokol.CreateEditProtokol(AOwner:TComponent;
DS:TDataSet;NazRadku:String);
begin
     inherited Create(nil{AOwner});

     if DS<>nil then
     begin
        dsRad.DataSet:=DS;
        FBeforePost:=DS.BeforePost;
        //DS.BeforePost:=cdsRad.BeforePost;
        FPocZmen:=(DS as TClientDataSet).ChangeCount;
        if DS.Active then
        begin
             DS.First;
             while not DS.Eof do
             begin
                  VytvorRadek(DS);
                  DS.Next;
             end;
             DS.First;
        end;
     end;
end;

metoda VytvorRadek je virtualni, ale i kdyz tam nebyla tak to padalo.


                                            Jaromir Cermak


-----Original Message-----
From: Petr Fejfar [mailto:development@callnet.cz]
Sent: Monday, November 22, 2004 12:25 PM
To: delphi-l@clexpert.cz
Subject: Re: Access violation v konstruktoru


Jaromir Cermak wrote:

> Taky to neni poprve co delam vlastni konstruktor, spis premyslim proc
> se preskoci instrukce

Mohl bys pls specifikovat, co mas na mysli tim "preskoci se"?

To jako ze ti debugger ukaze, ze instrukci vykonavana, ale zadna subrutina
se
nezavola?


Odpovedá: Petr Fejfar

22. 11. 2004 14:13

Jaromir Cermak wrote:

> constructor TFORP_EditProtokol.CreateEditProtokol(AOwner:TComponent;
> DS:TDataSet;NazRadku:String);
> begin
> inherited Create(nil{AOwner});
>
> if DS<>nil then
> begin
> dsRad.DataSet:=DS;
> FBeforePost:=DS.BeforePost;
> //DS.BeforePost:=cdsRad.BeforePost;
> FPocZmen:=(DS as TClientDataSet).ChangeCount;
> if DS.Active then
> begin
> DS.First;
> while not DS.Eof do
> begin
> VytvorRadek(DS);
> DS.Next;
> end;
> DS.First;
> end;
> end;
> end;

Ne ze bych ve tvem kodu videl co je spatne, ale obecne bych rekl,
ze tento chyb se vyskytuje "nechtenym" spustenim nejake event
mimo kontext tj. v dobe, kdy jeste neni konstrukce/inicializace
dokoncena popr. kdy nejsou predany vsechny argumenty,
jejich nespravne poradi apod.

***

Napada me - nezpusti se ti nejaka event - treba pri prirazeni
dsRad.DataSet:=DS; ?


HTH, pf


Odpovedá: Jaromir Cermak

22. 11. 2004 14:12

Uz jsem vyradil z constructoru vsechno, zustal jen radek s inherited, ale porad
to pada. Nemuze byt problem v .dfm. Na co se zamerit?



                                            Jaromir Cermak


-----Original Message-----
From: Petr Fejfar [mailto:development@callnet.cz]
Sent: Monday, November 22, 2004 1:25 PM
To: delphi-l@clexpert.cz
Subject: Re: Access violation v konstruktoru


Jaromir Cermak wrote:

> constructor TFORP_EditProtokol.CreateEditProtokol(AOwner:TComponent;
> DS:TDataSet;NazRadku:String);
> begin
> inherited Create(nil{AOwner});
>
> if DS<>nil then
> begin
> dsRad.DataSet:=DS;
> FBeforePost:=DS.BeforePost;
> //DS.BeforePost:=cdsRad.BeforePost;
> FPocZmen:=(DS as TClientDataSet).ChangeCount;
> if DS.Active then
> begin
> DS.First;
> while not DS.Eof do
> begin
> VytvorRadek(DS);
> DS.Next;
> end;
> DS.First;
> end;
> end;
> end;
 


Odpovedá: Petr Fejfar

22. 11. 2004 14:21

Jaromir Cermak wrote:

> Uz jsem vyradil z constructoru vsechno, zustal jen radek s inherited,
> ale porad to pada. Nemuze byt problem v .dfm. Na co se zamerit?

Pokud jsi ten formular vytvoril rucnim zkopirovanim mimo IDE,
tak snad jen zkontrolovat, jestli je definovan v .DFM jako potomek,
napr.

    inherited XHGBasalForm: TXHGBasalForm

Normalne je tam object, napr.

    object BIZAbstractForm: TBIZAbstractForm



BTW, predpokladam, ze dedis z TForm


pf



Odpovedá: Jaromir Cermak

24. 11. 2004 7:50

Jeste se vracim k problemu z pondelka.

Mam formular, ktery pri vytvareni v jistem kontextu generuje access violation.
Situace: Je- li vytvoren z nemodalniho okna => nespadne
V realnem umisteni: Volan jako treti vnorene modalni okno, pada spolehlive. Na
prikazu CreateNew(AOwner); konstruktoru TCustomForm.Create(nil).

Vyradil jsem i svuj vlastni konstruktor, abych to vyzkousel a vysledkem je ze
to furt pada.



                                            Jaromir Cermak